package com.piece.admin.service;

import com.piece.admin.model.TbSysDept;
import com.piece.admin.model.TbSysMenu;
import com.piece.admin.model.TbSysRole;
import com.piece.admin.model.TbSysUser;
import com.piece.admin.repository.TbSysRoleRepository;
import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.constant.FrameWorkConstants;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.enums.sql.SqlKey;
import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.exception.FrameWorkException;
import com.piece.core.framework.util.collection.ArrayUtil;
import com.piece.core.framework.util.collection.CollectionUtil;
import com.piece.core.framework.util.collection.MapUtil;
import com.piece.core.framework.util.object.BeanUtil;
import com.piece.core.framework.util.object.ObjectUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.jpa.repository.BaseService;
import com.piece.core.framework.support.bootstrap.Order;
import com.piece.core.framework.support.bootstrap.TreeData;
import com.piece.core.framework.support.convert.Convert;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色 业务层处理
 */
@Service
@Transactional
public class TbSysRoleService extends BaseService<TbSysRole, String> {

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    @Resource
    private TbSysRoleRepository tbSysRoleRepository;

    @PostConstruct
    public void initRepository() {
        setRepository(tbSysRoleRepository);
    }

    /**
     * 新增角色用户信息
     */
    public void insertRoleUser(TbSysRole role) {
        // 新增角色与用户
        if (StringUtil.isNotEmpty(role.getUserIds())) {
            Arrays.asList(Convert.toLongArray(role.getUserIds())).stream().forEach(userId -> {
                String sql = "insert into tb_sys_user_role(user_id,role_id) values(" + userId + " , " + role.getRoleId() + ")";
                tbSysRoleRepository.executeSql(sql);
            });
        }
    }

    /**
     * 新增角色菜单信息
     */
    public void insertRoleMenu(TbSysRole role) {
        // 新增角色与菜单
        if (StringUtil.isNotEmpty(role.getMenuIds())) {
            Arrays.asList(Convert.toLongArray(role.getMenuIds())).stream().forEach(menuId -> {
                String sql = "insert into tb_sys_role_menu(role_id,menu_id) values(" + role.getRoleId() + " , " + menuId + ")";
                tbSysRoleRepository.executeSql(sql);
            });
        }
    }

    /**
     * 新增角色部门信息(数据权限)
     */
    public void insertRoleDept(TbSysRole role) {
        // 新增角色与部门
        if (StringUtil.isNotEmpty(role.getDeptIds())) {
            Arrays.asList(Convert.toLongArray(role.getDeptIds())).stream().forEach(deptId -> {
                String sql = "insert into tb_sys_role_dept(role_id,dept_id) values(" + role.getRoleId() + " , " + deptId + ")";
                tbSysRoleRepository.executeSql(sql);
            });
        }
    }

    /**
     * 修改数据权限信息
     */
    public void updateRoleDept(TbSysRole role) {
        // 修改角色信息
        tbSysRoleRepository.update(role);
        // 删除角色与部门关联
        deleteRoleDeptByRoleId(role.getRoleId());
        if (null != role.getDeptIds()) {
            // 新增角色和部门信息（数据权限）
            insertRoleDept(role);
        }
    }

    /**
     * 修改角色菜单信息
     */
    public void updateRoleMenu(TbSysRole role) {
        // 修改角色信息
        tbSysRoleRepository.update(role);
        // 删除角色与菜单关联
        deleteRoleMenuByRoleId(role.getRoleId());
        if (null != role.getMenuIds()) {
            // 新增角色和菜单信息
            insertRoleMenu(role);
        }
    }

    /**
     * 修改角色用户信息
     */
    public void updateRoleUser(TbSysRole role) {
        // 修改角色信息
        tbSysRoleRepository.update(role);
        // 删除角色与用户关联
        deleteRoleUserByRoleId(role.getRoleId());
        if (null != role.getUserIds()) {
            // 新增角色和用户信息
            insertRoleUser(role);
        }
    }

    /**
     * 批量删除角色信息
     */
    @Override
    public int delete(Serializable[] ids) {
        for (Serializable roleId : ids) {
            TbSysRole role = findById(roleId);
            if (countUserRoleByRoleId((Long) roleId) > 0) {
                throw new FrameWorkException(new ErrorCode(ExceptionConstants.DELETE_ASSOCIATED, role.getRoleName()));
            }
            deleteRoleMenuByRoleId(Convert.toLong(roleId));
            deleteRoleDeptByRoleId(Convert.toLong(roleId));
        }
        return tbSysRoleRepository.delete(ids);
    }

    /**
     * 删除角色用户
     */
    public void deleteRoleUserByRoleId(long roleId) {
        tbSysRoleRepository.executeSql("delete from tb_sys_user_role where role_id = " + roleId + " ");
    }

    /**
     * 删除角色用户
     */
    public void deleteRoleUserByRoleId(long roleId, String userIds) {
        Arrays.asList(Convert.toLongArray(userIds)).stream().forEach(userId -> {
            String sql = "delete from tb_sys_user_role where role_id = " + roleId + " and user_id = " + userId;
            tbSysRoleRepository.executeSql(sql);
        });
    }

    /**
     * 删除角色菜单
     */
    public void deleteRoleMenuByRoleId(long roleId) {
        tbSysRoleRepository.executeSql("delete from tb_sys_role_menu where role_id = " + roleId + " ");
    }

    /**
     * 删除角色菜单
     */
    public void deleteRoleMenuByRoleId(long roleId, String menuIds) {
        Arrays.asList(Convert.toLongArray(menuIds)).stream().forEach(menuId -> {
            String sql = "delete from tb_sys_role_menu where role_id = " + roleId + " and menu_id = " + menuId;
            tbSysRoleRepository.executeSql(sql);
        });
    }

    /**
     * 删除角色部门
     */
    public void deleteRoleDeptByRoleId(long roleId) {
        tbSysRoleRepository.executeSql("delete from tb_sys_role_dept where role_id = " + roleId + " ");
    }

    /**
     * 删除角色部门
     */
    public void deleteRoleDeptByRoleId(long roleId, String deptIds) {
        Arrays.asList(Convert.toLongArray(deptIds)).stream().forEach(deptId -> {
            String sql = "delete from tb_sys_role_dept where role_id = " + roleId + " and dept_id = " + deptId;
            tbSysRoleRepository.executeSql(sql);
        });
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限ID列表
     */
    public Set<String> findPermsByUserId(Long userId) {
        String sql = "select distinct r.role_key from tb_sys_role r " +
                "left join tb_sys_user_role ur on r.role_id = ur.role_id " +
                "where r.role_key is not null and user_id = " + userId +
                " and status = '" + StatusType.NORMAL.getCode() + "' " +
                " union " +
                "select distinct m.perms from tb_sys_menu m " +
                "left join tb_sys_role_menu rm on m.menu_id = rm.menu_id " +
                "left join tb_sys_user_role ur on rm.role_id = ur.role_id " +
                "where m.perms is not null and user_id = " + userId + " ";
        List<String> perms = jdbcTemplate.queryForList(sql, String.class);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            permsSet.addAll(Arrays.asList(perm.trim().split(FrameWorkConstants.SPLIT_PARAM)));
        }
        return permsSet;
    }

    /**
     * 根据用户ID查询角色
     *
     * @param userId 用户ID
     * @return 所有角色列表
     */
    public List<TbSysRole> findRolesByUserId(Long userId) {
        String sql = "select * from tb_sys_role r " +
                "left join tb_sys_user_role ur on r.role_id = ur.role_id " +
                "where r.role_key is not null and user_id = " + userId +
                " and status = '" + StatusType.NORMAL.getCode() + "' order by role_sort asc";
        List<TbSysRole> userRoles = jdbcTemplate.queryForList(sql, TbSysRole.class);
        List<TbSysRole> roles = findAll();
        for (TbSysRole role : roles) {
            for (TbSysRole userRole : userRoles) {
                if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
                    role.setFlag(true);
                }
            }
        }
        return roles;
    }

    /**
     * 查询角色树
     */
    public List<TreeData> findTreeData() {
        List<TreeData> trees;
        List<TbSysRole> roleList = findAll();
        trees = findTreeData(roleList, false, null);
        return trees;
    }

    /**
     * 对象转角色树
     *
     * @param roleList        角色列表
     * @param isCheck         是否需要选中
     * @param roleCheckedList 角色已存在部门列表
     * @return
     */
    public List<TreeData> findTreeData(List<TbSysRole> roleList, boolean isCheck, List<String> roleCheckedList) {
        List<TreeData> trees = new ArrayList<>();
        for (TbSysRole role : roleList) {
            TreeData treeData = TreeData.builder()
                    .id(String.valueOf(role.getRoleId()))
                    .pId("0")
                    .title(role.getRoleName())
                    .name(role.getRoleName())
                    .build();

            if (isCheck) {
                treeData.setChecked(roleCheckedList.contains(role.getRoleId().toString()));
            } else {
                treeData.setChecked(false);
            }
            trees.add(treeData);
        }
        return trees;
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param roleName 角色名称
     * @return true: 通过 false: 重复
     */
    public boolean checkRoleNameUnique(String roleName) {
        String hql = "from TbSysRole where roleName = ?0 and status = ?1 ";
        long count = tbSysRoleRepository.count(hql, new Object[]{roleName, StatusType.NORMAL.getCode()}, true);
        return count <= 0;
    }

    /**
     * 校验角色权限标识是否唯一
     *
     * @param roleKey 角色权限标识
     * @return true: 通过 false: 重复
     */
    public boolean checkRoleKeyUnique(String roleKey) {
        String hql = "from TbSysRole where roleKey = ?0 and status = ?1 ";
        long count = tbSysRoleRepository.count(hql, new Object[]{roleKey, StatusType.NORMAL.getCode()}, true);
        return count <= 0;
    }

    /**
     * 通过角色ID查询角色使用数量
     */
    public int countUserRoleByRoleId(Long roleId) {
        String hql = "select role_id from tb_sys_user_role where role_id = ?0";
        Long count = tbSysRoleRepository.count(hql, new Object[]{roleId}, false);
        return null == count ? 0 : count.intValue();
    }

    /**
     * 根据所有用户角色关联列表
     */
    public List<String[]> findAllUserRoleList() {
        String sql = "select ur.user_id user, ur.role_id role from tb_sys_user_role ur";
        List<Map<String, Object>> result = jdbcTemplate.queryForList(sql);
        List<String[]> returnList = new ArrayList<>();
        if (ArrayUtil.isNotEmpty(result)) {
            result.stream().forEach(map -> {
                returnList.add(new String[]{Convert.toStr(map.get("user"), ""), Convert.toStr(map.get("role"), "")});
            });
        }
        return returnList;
    }

    /**
     * 设置菜单组、部门组相关信息
     */
    public void setOtherInfo(TbSysRole role) {
        // 设置菜单组
        String sql = "select * from tb_sys_menu where menu_id in(select menu_id from tb_sys_role_menu where role_id = " + role.getRoleId() + ") ";
        List<TbSysMenu> menus = jdbcTemplate.query(sql, (rs, rowNum) -> {
            TbSysMenu menu = new TbSysMenu();
            BeanUtil.resultSetToBean(rs, menu);
            return menu;
        });
        List<Long> menuIds;
        List<String> menuNames;
        if (null != menus) {
            menuIds = new ArrayList<>();
            menuNames = new ArrayList<>();
            for (TbSysMenu menu : menus) {
                menuIds.add(menu.getMenuId());
                menuNames.add(menu.getMenuName());
            }
            role.setMenuIds(Arrays.stream(menuIds.toArray()).map(p -> Convert.toStr(p)).collect(Collectors.joining(FrameWorkConstants.SPLIT_PARAM)));
            role.setMenuNames(Arrays.stream(menuNames.toArray()).map(p -> Convert.toStr(p)).collect(Collectors.joining(FrameWorkConstants.SPLIT_PARAM)));
        }

        // 设置部门组
        sql = "select * from tb_sys_dept where dept_id in(select dept_id from tb_sys_role_dept where role_id = " + role.getRoleId() + ") ";
        List<TbSysDept> depts = jdbcTemplate.query(sql, (rs, rowNum) -> {
            TbSysDept dept = new TbSysDept();
            BeanUtil.resultSetToBean(rs, dept);
            return dept;
        });
        List<Long> deptIds;
        List<String> deptNames;
        if (null != depts) {
            deptIds = new ArrayList<>();
            deptNames = new ArrayList<>();
            for (TbSysDept dept : depts) {
                deptIds.add(dept.getDeptId());
                deptNames.add(dept.getDeptName());
            }
            role.setDeptIds(Arrays.stream(deptIds.toArray()).map(p -> Convert.toStr(p)).collect(Collectors.joining(FrameWorkConstants.SPLIT_PARAM)));
            role.setDeptNames(Arrays.stream(deptNames.toArray()).map(p -> Convert.toStr(p)).collect(Collectors.joining(FrameWorkConstants.SPLIT_PARAM)));
        }

        // 设置用户组
        sql = "select * from tb_sys_user where user_id in(select user_id from tb_sys_user_role where role_id = " + role.getRoleId() + ") ";
        List<TbSysUser> users = jdbcTemplate.query(sql, (rs, rowNum) -> {
            TbSysUser user = new TbSysUser();
            BeanUtil.resultSetToBean(rs, user);
            return user;
        });
        List<Long> userIds;
        List<String> userNames;
        if (null != users) {
            userIds = new ArrayList<>();
            userNames = new ArrayList<>();
            for (TbSysUser user : users) {
                userIds.add(user.getUserId());
                userNames.add(user.getUserName());
            }
            role.setUserIds(Arrays.stream(userIds.toArray()).map(p -> Convert.toStr(p)).collect(Collectors.joining(FrameWorkConstants.SPLIT_PARAM)));
            role.setUserNames(Arrays.stream(userNames.toArray()).map(p -> Convert.toStr(p)).collect(Collectors.joining(FrameWorkConstants.SPLIT_PARAM)));
        }
    }

    public String convertIdToName(String ids) {
        String sql = "select role_name from tb_sys_role where role_id in (:roleIds)";
        Map<String, Object> param = new HashMap<>();
        param.put("roleIds", Convert.toLongList(ids));
        List<String> names = namedParameterJdbcTemplate.queryForList(sql, param, String.class);
        if (names.size() > 0) {
            return StringUtil.join(names, FrameWorkConstants.SPLIT_PARAM);
        }
        return "";
    }

    public void validRole(Collection<Long> ids) {
        if (ObjectUtil.isEmpty(ids)) {
            return;
        }

        List<TbSysRole> roles = tbSysRoleRepository.findByCondition(MapUtil.builder(new HashMap<String, Object>())
                .put("roleId", new ArrayList<>(ids))
                .put("status", StatusType.NORMAL.getCode())
                .build(), null);
        Map<Long, TbSysRole> roleMap = CollectionUtil.convertMap(roles, TbSysRole::getRoleId);
        ids.forEach(id -> {
            TbSysRole role = roleMap.get(id);
            if (null == role) {
                throw new FrameWorkException(new ErrorCode(ExceptionConstants.NOT_EXIST, "角色【" + id + "】"));
            }

            if (!StatusType.NORMAL.getCode().equals(role.getStatus())) {
                throw new FrameWorkException(new ErrorCode(ExceptionConstants.IS_DISABLE, role.getRoleName()));
            }
        });
    }

    @Override
    protected List<Order> generateDefaultOrder() {
        List<Order> orders = new ArrayList<>();
        orders.add(new Order("roleSort", SqlKey.ASC));
        return orders;
    }
}
